package org.zero.util;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Objects;

/**
 * @author Zero (cnzeropro@qq.com)
 * @date 2021/9/1 17:02
 */
@Slf4j
@UtilityClass
public class EnumUtils {

    /**
     * 获取指定名称的枚举对象
     *
     * @param enumType
     * @param name
     * @param <E>
     * @return
     */
    public <E extends Enum<E>> E getEnumByName(Class<E> enumType, String name) {
        for (E enumObj : enumType.getEnumConstants()) {
            if (enumObj.name().equalsIgnoreCase(name)) {
                return enumObj;
            }
        }
        return null;
    }

    /**
     * 获取含有指定属性值的枚举对象
     *
     * @param enumType
     * @param key
     * @param <E>
     * @return
     */
    public <E extends Enum<E>> E getEnum(Class<E> enumType, Object key) {
        Field[] fields = enumType.getDeclaredFields();
        try {
            for (E enumObj : enumType.getEnumConstants()) {
                for (Field field : fields) {
                    field.setAccessible(true);
                    Object obj = field.get(enumObj);

                    if (Objects.isNull(obj)) {
                        continue;
                    }
                    // 数字类型比较
                    if (obj instanceof Number && key instanceof Number) {
                        BigDecimal numObj = new BigDecimal(String.valueOf(obj));
                        BigDecimal numKey = new BigDecimal(String.valueOf(key));
                        if (numObj.compareTo(numKey) == 0) {
                            return enumObj;
                        }
                    } else {
                        if (Objects.equals(key, obj)) {
                            return enumObj;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 从枚举中获取指定类型的第一个属性值
     *
     * @param enumObj
     * @param keyType
     * @param <K>
     * @param <E>
     * @return
     */
    public <K, E extends Enum<E>> K getKey(E enumObj, Class<K> keyType) {
        Field[] fields = enumObj.getDeclaringClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                if (Objects.equals(field.getType(), keyType)) {
                    field.setAccessible(true);
                    return (K) field.get(enumObj);
                }
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 从枚举中获取含有指定名称的属性值
     *
     * @param enumObj
     * @param keyName
     * @param <E>
     * @return
     */
    public <E extends Enum<E>> Object getKey(E enumObj, String keyName) {
        Field[] fields = enumObj.getDeclaringClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                if (field.getName().equalsIgnoreCase(keyName)) {
                    field.setAccessible(true);
                    return field.get(enumObj);
                }
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 从枚举中获取含有指定名称的属性值，并封装成指定类型
     *
     * @param enumObj
     * @param keyName
     * @param keyType
     * @param <K>
     * @param <E>
     * @return
     */
    public <K, E extends Enum<E>> K getKey(E enumObj, String keyName, Class<K> keyType) {
        Field[] fields = enumObj.getDeclaringClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                if (field.getName().equalsIgnoreCase(keyName)) {
                    field.setAccessible(true);
                    return (K) field.get(enumObj);
                }
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 从指定属性值的枚举中获取含有指定名称的属性值
     *
     * @param enumType
     * @param key
     * @param otherKeyName
     * @param <E>
     * @return
     */
    public <E extends Enum<E>> Object getOtherKey(Class<E> enumType, Object key, String otherKeyName) {
        return getKey(getEnum(enumType, key), otherKeyName);
    }

    /**
     * 从指定属性值的枚举中获取含有指定名称的属性值，并封装成指定类型
     *
     * @param enumType
     * @param key
     * @param otherKeyName
     * @param otherKeyType
     * @param <K>
     * @param <E>
     * @return
     */
    public <K, E extends Enum<E>> K getOtherKey(Class<E> enumType, Object key, String otherKeyName, Class<K> otherKeyType) {
        return getKey(getEnum(enumType, key), otherKeyName, otherKeyType);
    }
}
